--------------------------------------------------------------------------
--[[ ForestResourceSpawner class definition ]]
--------------------------------------------------------------------------

return Class(function(self, inst)

assert(TheWorld.ismastersim, "ForestResourceSpawner should not exist on client")

--------------------------------------------------------------------------
--[[ Dependencies ]]
--------------------------------------------------------------------------

local easing = require("easing")

--------------------------------------------------------------------------
--[[ Constants ]]
--------------------------------------------------------------------------

local MIN_PLAYER_DISTANCE = 240
local RENEW_RADIUS = 60
local RENEWABLES =
{
    flint = { flint = true },
    sapling = { sapling = true },
    grass = { grass = true, depleted_grass = true },
    berrybush = { berrybush = true, berrybush2 = true },
}

--------------------------------------------------------------------------
--[[ Member variables ]]
--------------------------------------------------------------------------

--Public
self.inst = inst

--Private
local _enabled = false
local _spawnpts = {}
local _task = nil

--------------------------------------------------------------------------
--[[ Private member functions ]]
--------------------------------------------------------------------------

local function GetRenewablePeriod()
    return TUNING.SEG_TIME + math.random() * TUNING.SEG_TIME
end

local function DoPrefabRenew(x, z, ents, prefab, prefab_matches, max)
    --Check if this prefab was found already
    for i, v in ipairs(ents) do
        if prefab_matches[v.prefab] then
            return
        end
    end

    --Spawn random up to max count
    for i = math.random(max), 1, -1 do
        local theta = math.random() * 2 * PI
        local radius = math.random() * RENEW_RADIUS
        local x1 = x + radius * math.cos(theta)
        local z1 = z - radius * math.sin(theta)
        if inst.Map:CanPlantAtPoint(x1, 0, z1) then
            SpawnPrefab(prefab).Transform:SetPosition(x1, 0, z1)
        end
    end
end

local function DoRenew()
    local targeti = math.min(math.floor(easing.inQuint(math.random(), 1, #_spawnpts, 1)), #_spawnpts)
    local target = _spawnpts[targeti]
    table.remove(_spawnpts, targeti)
    table.insert(_spawnpts, target)

    local x, y, z = target.Transform:GetWorldPosition()
    if not IsAnyPlayerInRange(x, y, z, MIN_PLAYER_DISTANCE) then
        local ents = TheSim:FindEntities(x, y, z, RENEW_RADIUS, { "renewable" })
        for k, v in pairs(RENEWABLES) do
            DoPrefabRenew(x, z, ents, k, v, 3)
        end
    end

    _task = inst:DoTaskInTime(GetRenewablePeriod(), DoRenew)
end

local function Start()
    if _task == nil then
        _task = inst:DoTaskInTime(GetRenewablePeriod(), DoRenew)
    end
end

local function Stop()
    if _task ~= nil then
        _task:Cancel()
        _task = nil
    end
end

--------------------------------------------------------------------------
--[[ Private event handlers ]]
--------------------------------------------------------------------------

local function UnregisterSpawnPoint(spawnpt)
    if spawnpt == nil then
        return
    end
    RemoveByValue(_spawnpts, spawnpt)
end

local function OnRegisterSpawnPoint(inst, spawnpt)
    if spawnpt == nil or
        table.contains(_spawnpts, spawnpt) then
        return
    end
    table.insert(_spawnpts, spawnpt)
    inst:ListenForEvent("onremove", UnregisterSpawnPoint, spawnpt)
end

local function OnEnableResourceRenewal(inst, enable)
    if _enabled ~= enable then
        _enabled = enable
        if enable then
            Start()
        else
            Stop()
        end
    end
end

--------------------------------------------------------------------------
--[[ Initialization ]]
--------------------------------------------------------------------------

inst:ListenForEvent("ms_registerspawnpoint", OnRegisterSpawnPoint)
inst:ListenForEvent("ms_enableresourcerenewal", OnEnableResourceRenewal)

if _enabled then
    Start()
end

--------------------------------------------------------------------------
--[[ End ]]
--------------------------------------------------------------------------

end)
